package org.bookie.framework.services.impl;

import java.io.IOException;

import javax.mail.MessagingException;

import org.apache.commons.logging.Log;
import org.apache.tapestry.IRequestCycle;
import org.apache.tapestry.RedirectException;
import org.apache.tapestry.engine.IEngineService;
import org.bookie.core.model.FacebookUser;
import org.bookie.core.services.IAuthenticationContext;
import org.bookie.core.services.IFacebookClient;
import org.bookie.core.services.IUserManager;
import org.bookie.core.services.IAuthenticationContext.AuthenticationResult;
import org.bookie.core.services.IUserManager.RegistrationResult;
import org.bookie.model.User;

import com.facebook.api.FacebookException;

/**
 * {@link IEngineService} executing authentication from the Facebook
 * 
 * @author zubairov
 */
public class FacebookAuthEngineServiceImpl extends CommonEngineService {

	private static final String FACEBOOK_USER_EMAIL_SUFFIX = "@users.facebook.org";
	
	private static final String SERVICE_NAME = "facebook";
	
	private static final String FACEBOOK_AUTH_TOKEN = "auth_token";
	
	private Log log;

	private IAuthenticationContext ctx;
	
	private IUserManager userManager;
	
	private IFacebookClient client;
	
	public String getName() {
		return SERVICE_NAME;
	}

	public void service(IRequestCycle cycle) throws IOException {
		String url = cycle.getAbsoluteURL("/");
		String token = request.getParameterValue(FACEBOOK_AUTH_TOKEN);
		if (token == null) {
			log.error("Facecbook authenticated without parameter " + FACEBOOK_AUTH_TOKEN);
			throw new RedirectException(url);
		}
		try {
			client.authenticate(token);
			FacebookUser fbuser = client.getAuthenticatedUser();
			log.debug("Found user '" + fbuser.getName() + "' authenticated in facebook");
			String email = fbuser.getId() + FACEBOOK_USER_EMAIL_SUFFIX;
			AuthenticationResult res = ctx.authenticate(email);
			if (res == AuthenticationResult.USER_NOT_FOUND) {
				User user = new User(fbuser.getName(), String.valueOf(System.currentTimeMillis()), email);
				RegistrationResult regRes = userManager.registerNewUser(user, false);
				if (regRes != RegistrationResult.OK) {
					log.error("Can't add new user " + user + " because of " + regRes);
				}
				AuthenticationResult authRes = ctx.authenticate(email);
				if (authRes != AuthenticationResult.SUCCESS) {
					log.error("Can't authenticate user even after it was added, becaue of" + authRes);
				}
			}
		} catch (FacebookException e) {
			log.error("Exception while accessing facebook", e);
			throw new RuntimeException(e);
		} catch (MessagingException e) {
			log.error("Error sending email, shall not appear", e);
			throw new RuntimeException(e);
		} 
		throw new RedirectException(url);
	}

	/**
	 * Injector for {@link #log}
	 * 
	 * @category injector
	 * @param log
	 */
	public void setLog(Log log) {
		this.log = log;
	}
	
	/**
	 * @category injector
	 * @param ctx
	 */
	public void setCtx(IAuthenticationContext ctx) {
		this.ctx = ctx;
	}
	
	/**
	 * @category injector
	 * @param userManager
	 */
	public void setUserManager(IUserManager userManager) {
		this.userManager = userManager;
	}
	
	/**
	 * @category injector
	 * @param client
	 */
	public void setClient(IFacebookClient client) {
		this.client = client;
	}
	
}
